#pragma once

#include <iostream>
#include <filesystem>
#include <memory>
#include <unistd.h>
#include <sstream>
#include <fstream>
#include <ctime>
#include <sys/types.h>
#include <sys/wait.h>

class HandlerText
{
public:
    HandlerText() : _enable(true)
    {
    }
    virtual ~HandlerText() = default;
    void SetNextHandler(std::shared_ptr<HandlerText> handler)
    {
        _next_handler = handler;
    }
    void Enable() { _enable = true; }
    void DisEnable() { _enable = false; }
    bool IsEnable() { return _enable; }

    virtual void Execute(std::string &info) = 0;

protected: // 这里要protected，方便继承
    std::shared_ptr<HandlerText> _next_handler;
    bool _enable;
};

class HandlerTextFormat : public HandlerText
{
public:
    ~HandlerTextFormat()
    {
    }
    void Execute(std::string &info) override
    {
        if (HandlerText::IsEnable())
        {
            // 开始处理，添加简单的补充信息
            std::cout << "Format ..." << std::endl;
            // 简单处理
            std::stringstream ss;
            ss << time(nullptr) << " - " << getpid() << " - " << info << "\n";
            info = ss.str();

            sleep(1);
        }
        if (_next_handler) // 如果_next_handler被设置，就交给下一个继续加工处理
            _next_handler->Execute(info);
        else
            std::cout << "责任链节点结束,处理完成" << std::endl;
    }
};

std::string defaultpath = "./tmp/";
std::string defaultfilename = "test.log";

class HandlerTextSaveFile : public HandlerText
{
public:
    HandlerTextSaveFile() : _filepath(defaultpath), _filename(defaultfilename)
    {
        if (std::filesystem::exists(_filepath))
            return;

        try
        {
            std::filesystem::create_directories(_filepath);
        }
        catch (std::filesystem::filesystem_error &e)
        {
            std::cerr << e.what() << std::endl;
        }
    }
    ~HandlerTextSaveFile()
    {
    }
    void Execute(std::string &info) override
    {
        if (HandlerText::IsEnable())
        {
            // 开始处理,保存到指定的文件中
            std::cout << "Save ..." << std::endl;
            sleep(1);
            const std::string file = _filepath + _filename;
            std::ofstream out(file, std::ios::app);
            if (!out.is_open())
                return;
            out << info;
            out.close();
        }
        if (_next_handler) // 如果_next_handler被设置，就交给下一个继续加工处理
            _next_handler->Execute(info);
        else
            std::cout << "责任链节点结束,处理完成" << std::endl;
    }

private:
    std::string _filepath;
    std::string _filename;
};

const int maxline = 5; // 为了尽快触发备份动作，该值设置小一些

class HandlerTextBackupFile : public HandlerText
{
public:
    HandlerTextBackupFile() : _max_line_number(maxline), _filepath(defaultpath), _filename(defaultfilename)
    {
    }
    ~HandlerTextBackupFile()
    {
    }
    void Execute(std::string &info) override
    {
        if (HandlerText::IsEnable())
        {
            // 开始处理，对文件进行增量备份
            std::cout << "Backup ..." << std::endl;
            sleep(1);
            const std::string filename = _filepath + _filename;
            // 1. 打开文件
            std::ifstream in(filename);
            if (!in.is_open())
                return;
            std::string line;
            int currentlines = 0;
            while (std::getline(in, line))
            {
                currentlines++;
            }
            // 关闭文件流
            in.close();

            // 2. 备份
            if (currentlines > _max_line_number)
            {
                std::cout << "消息行数超过" << _max_line_number << ", 触发日志备份" << std::endl;
                // 大于才做备份，否则什么走不做
                Backup();
            }
        }
        if (_next_handler) // 如果_next_handler被设置，就交给下一个继续加工处理
            _next_handler->Execute(info);
        else
            std::cout << "责任链节点结束,处理完成" << std::endl;
    }

    void Backup()
    {
        std::string newname = _filename + "." + std::to_string(time(nullptr));
        pid_t id = fork();
        if (id == 0)
        {
            chdir(_filepath.c_str()); // 更改进程路径，进入"./tmp/"路径下
            std::filesystem::rename(_filename, newname); // rename比较快，也不影响未来其他继续写入的操作，因为会重新形成文件
            std::string tarname = newname + ".tgz";
            // 子进程打包备份
            std::cout << "打包 : " << newname << " 成为: " << tarname << "开始" << std::endl;
            execlp("tar", "tar", "czf", tarname.c_str(), newname.c_str(), nullptr); // 注意这里要以nullptr结尾，注意这里的坑
            std::cout << "打包 : " << newname << " 成为: " << tarname << "失败" << std::endl;
            exit(1);
        }
        waitpid(id, nullptr, 0);
        std::string tempfile = _filepath + newname;
        std::filesystem::remove(tempfile); // 删除文件原件，只要tar包
    }

private:
    int _max_line_number;
    std::string _filepath;
    std::string _filename;
};

class HandlerEntry
{
public:
    HandlerEntry()
    {
        // 构建责任链节点对象
        _format = std::make_shared<HandlerTextFormat>();
        _save = std::make_shared<HandlerTextSaveFile>();
        _backup = std::make_shared<HandlerTextBackupFile>();

        // 链接责任链
        _format->SetNextHandler(_save);
        _save->SetNextHandler(_backup);
    }
    void EnableHandler(bool isformat, bool issave, bool isbackup)
    {
        isformat ? _format->Enable() : _format->DisEnable();
        issave ? _save->Enable() : _save->DisEnable();
        isbackup ? _backup->Enable() : _backup->DisEnable();
    }
    void Run(std::string &info)
    {
        _format->Execute(info);
    }

private:
    std::shared_ptr<HandlerText> _format;
    std::shared_ptr<HandlerText> _save;
    std::shared_ptr<HandlerText> _backup;
};
